import { Spin } from "antd";
import { useEffect, useMemo, useRef, type PropsWithChildren } from "react";
import { Link } from "react-router";
import { useAtomValue } from "jotai";
import useFetch from "@/lib/hooks/useFetch";
import { getDeviceStatusList } from "@/lib/api/deviceStatus";
import { tokenAtom } from "@/store/user";
import type { IDeviceStatus } from "@/lib/types";
import { getRegionList } from "@/lib/api/region";
import InfiniteScroll from "@/components/InfiniteScroll";
import useOnMounted from "@/lib/hooks/useOnMounted";
import TemperatureIcon from "@/assets/icons/temperature.svg?jsx";
import WaterIcon from "@/assets/images/water.png?jsx";
import PressureGaugeIcon from "@/assets/images/pressure-gauge.png?jsx";
import LinkIcon from "@/assets/images/link.png?jsx";
import UnlinkIcon from "@/assets/images/unlink.png?jsx";
import AlertIcon from "@/assets/icons/alert.svg?jsx";
import { useAudioPlayer } from "@/providers/AudioPlayerProvider";
import clsm from "@/lib/utils/clsm";
import LongScrollText from "@/components/LongScrollText";
import { useDeviceContext } from "@/providers/DeviceProvider";

export default function Chart() {
  const token = useAtomValue(tokenAtom);
  const player = useAudioPlayer();
  const { onDeviceListChange } = useDeviceContext();

  const {
    data,
    isPending,
    isLoading,
    refetch: laodDeviceStatusList,
    cancel: cancelLaodDeviceStatusList,
  } = useFetch({
    fetchFn: (signal) =>
      getDeviceStatusList(token, signal).then((res) => {
        if (res.code !== 200) {
          throw res;
        }
        return res.data;
      }),
    onSuccess(data) {
      try {
        onDeviceListChange(data);
        if (data.find((item) => item.alarms.length)) {
          player.play("alert");
        }
      } catch (error) {
        console.log(error);
      }
    },
  });

  const { data: regionList } = useFetch({
    fetchFn: (signal) =>
      getRegionList({}, token, signal).then((res) => {
        if (res.code !== 200) {
          throw res;
        }
        return res.rows;
      }),
    immediate: true,
  });

  useOnMounted(() => {
    let timer: Timer;

    function loop() {
      laodDeviceStatusList();
      timer = setTimeout(loop, 5000);
    }

    loop();

    return () => {
      cancelLaodDeviceStatusList();
      clearTimeout(timer);
    };
  });

  const groupData = useMemo(() => {
    const regionMap = new Map<number, string>();
    const deviceMap = new Map<number, IDeviceStatus[]>();
    data?.forEach((device) => {
      const list = deviceMap.get(device.regionId) || [];
      list.push(device);
      deviceMap.set(device.regionId, list);
    });
    regionList?.forEach((region) => {
      regionMap.set(region.regionId, region.regionName);
    });

    const SortSpec = {
      "2": 1, // 运行
      "3": 2, // 保持
      "1": 3, // 停机
    };

    return Array.from(deviceMap.entries()).map(([regionId, devices]) => ({
      regionId,
      regionName: regionMap.get(regionId) || "-",
      devices: devices.sort(
        (a, b) => SortSpec[a.deviceStatus] - SortSpec[b.deviceStatus],
      ),
    }));
  }, [data, regionList]);

  if (isPending || !data) {
    return (
      <Spin size="large">
        <div className="h-40" />
      </Spin>
    );
  }

  return (
    <div className="grid grid-cols-3 gap-x-6 px-8 py-4">
      {groupData.map((item) => (
        <div key={item.regionId} className="">
          <div className="text-center text-sm text-green-500">
            {item.regionName}
          </div>
          <div className="grid grid-cols-2 gap-4 rounded border border-dashed p-4">
            {item.devices.map((status) => (
              <DeviceStatus key={status.deviceId} device={status} />
            ))}
          </div>
        </div>
      ))}
    </div>
  );
}

type DeviceStatusProps = {
  device: IDeviceStatus;
};
function DeviceStatus(props: DeviceStatusProps) {
  const { device } = props;

  const scrollBoxRef = useRef<HTMLDivElement>(null);
  const statusText =
    device.status === "0"
      ? "停用"
      : device.deviceControl
        ? "设备端控制中"
        : device.deviceStatus === "1"
          ? "待机中"
          : device.deviceStatus === "2"
            ? "运行中"
            : "保持中";
  const suspend = device.deviceStatus === "1";

  useOnMounted(() => {
    let timer: Timer;
    function autoScroll() {
      timer = setTimeout(() => {
        const { scrollWidth, clientWidth, scrollLeft } = scrollBoxRef.current!;
        if (Math.abs(scrollLeft + clientWidth - scrollWidth) < 3) {
          scrollBoxRef.current!.scrollLeft = 0;
        } else {
          scrollBoxRef.current!.scrollLeft += clientWidth;
        }
        autoScroll();
      }, 3000);
    }
    autoScroll();

    return () => {
      clearTimeout(timer);
    };
  });

  return (
    <Link to={`/dashboard/${device.deviceId}`}>
      <div className="bg-[#262626] p-1 text-sm">
        <div className="flex items-center border-b px-2 pb-2">
          <div className="flex-none">
            {device.conn ? (
              <>
                <span
                  className={clsm(
                    "mr-3",
                    (device.deviceStatus !== "1" || device.deviceControl) &&
                      "text-[#22C55E]",
                  )}
                >
                  {statusText}
                </span>
                <LinkIcon className="inline h-4 -rotate-90" />
              </>
            ) : (
              <UnlinkIcon className="inline h-4 -rotate-90" />
            )}
          </div>
          <LongScrollText
            className={clsm(
              "min-w-0 flex-auto",
              device.status === "0" && "text-red-500",
            )}
          >
            {device.deviceName}
          </LongScrollText>
        </div>
        <div
          className="snap-x snap-mandatory overflow-hidden scroll-smooth whitespace-nowrap *:snap-center"
          ref={scrollBoxRef}
        >
          {device.isTemperature === 1 && (
            <Detail
              type="temperature"
              pv={device.tPv}
              sv={device.t ? device.tSv : "OFF"}
              status={device.tStatus}
              suspend={suspend}
              leftTime={device.isTime ? device.tLeftTime : Infinity}
              deviceControl={device.deviceControl}
            />
          )}
          {device.isHumidity === 1 && (
            <Detail
              type="humidity"
              pv={device.hPv}
              sv={device.h ? device.hSv : "OFF"}
              status={device.hStatus}
              suspend={suspend}
              leftTime={device.isTime ? device.hLeftTime : Infinity}
              deviceControl={device.deviceControl}
            />
          )}
          {device.isPressure === 1 && (
            <Detail
              type="pressure"
              pv={device.pPv}
              sv={device.p ? device.pSv : "OFF"}
              status={device.pStatus}
              suspend={suspend}
              leftTime={device.isTime ? device.pLeftTime : Infinity}
              deviceControl={device.deviceControl}
            />
          )}
        </div>
        <InfiniteScroll className="h-6 py-0.5">
          {device.alarms.map((alarm) => (
            <InfiniteScroll.Item key={alarm.alarmName} className="text-red-500">
              <AlertIcon />
              <span className="flex-auto text-center">{alarm.alarmName}</span>
            </InfiniteScroll.Item>
          ))}
          {device.warnings.map((warning) => (
            <InfiniteScroll.Item
              key={warning.warningName}
              className="text-red-500"
            >
              <AlertIcon />
              <span className="flex-auto text-center">
                {warning.warningName}
              </span>
            </InfiniteScroll.Item>
          ))}
        </InfiniteScroll>
      </div>
    </Link>
  );
}

const Title = {
  temperature: "温度",
  humidity: "湿度",
  pressure: "压力",
};
const Status = {
  temperature: {
    0: "降温",
    1: "保温",
    2: "升温",
  },
  humidity: {
    0: "去湿",
    1: "保湿",
    2: "加湿",
  },
  pressure: {
    0: "降压",
    1: "保持",
    2: "增压",
  },
};
type DetailProps = {
  type: "temperature" | "humidity" | "pressure";
  pv: number; // 采样值
  sv: number | string; // 设定值
  status: -1 | 0 | 1; // 状态
  leftTime: number;
  suspend: boolean;
  deviceControl: boolean;
};
function Detail(props: DetailProps) {
  const { type, pv, sv, status, leftTime, suspend, deviceControl } = props;
  const statusText = Status[type][(status + 1) as 0 | 1 | 2];
  return (
    <div className="relative inline-block w-full px-2 py-4">
      <div className="absolute right-1 top-1">
        <span className="mr-1">{Title[type]}</span>
        {type === "temperature" && <TemperatureIcon className="inline h-8" />}
        {type === "humidity" && <WaterIcon className="inline h-8" />}
        {type === "pressure" && <PressureGaugeIcon className="inline h-8" />}
      </div>
      <div className="text-3xl">{pv.toFixed(1)}</div>
      <div className="flex leading-6 *:basis-1/2">
        <div>
          <div>
            <span>设定值：</span>
            <span>{typeof sv === "number" ? sv.toFixed(1) : sv}</span>
          </div>
          {!suspend && !deviceControl && (
            <div>
              <span>状态：</span>
              <span className="text-yellow-500">{statusText}</span>
            </div>
          )}
        </div>
        {!suspend && !deviceControl && (
          <div>
            <div>{statusText}剩余</div>
            <div className="text-green-400">{normalizeTime(leftTime)}</div>
          </div>
        )}
      </div>
    </div>
  );
}

function normalizeTime(duration: number) {
  if (!Number.isFinite(duration)) {
    return "∞";
  }
  const seconds = duration % 60;
  const minutes = Math.floor(duration / 60) % 60;
  const hours = Math.floor(duration / 60 / 60) % 60;
  const padStart = (n: number) => String(n).padStart(2, "0");
  return `${padStart(hours)}:${padStart(minutes)}:${padStart(seconds)}`;
}
